<?php
/**
 * > データモデル
 *
 * データを保持するコンテナ。
 *
 * LICENSE: Miracle Maple by Mirage is licensed
 * under a Creative Commons 表示-非営利-継承 2.1 日本 License.
 *
 * @category   model
 * @package    maple-story.jp
 * @version    8.0.0
 * @link       http://maple-story.jp/
 * @since      File available since Release 8.0.0
 * @copyright  Copyright 2011 Miracle Maple
 * @license    http://creativecommons.org/licenses/by-nc-sa/2.1/jp/     Creative Commons BY-NC-SA
 */
abstract class Model_ModelAbstract
{
    /**
     * @var array
     */
    protected $_column = array();

    /**
     * @var Model_MapperAbstract
     */
    protected $_mapper;

    /**
     * カラムにデータをセット (マジックメソッド)
     * 
     * @param  string $name 
     * @param  mixed $value 
     * @return void
     */
    public function __set($name, $value)
    {
        $this->_column[$name] = $value;
        return $this;
    }

    /**
     * カラムのデータを取得 (マジックメソッド)
     * 
     * @param  string $name 
     * @return mixed
     */
    public function __get($name)
    {
        if (!isset($this->_column[$name])) {
            $logger = Zend_Registry::get('APPLICATION_LOG');
            $logger->notice(__FILE__ . ' [' . __LINE__ . '] : ' . $name . ' is not set.');
            return null;
        }
        return $this->_column[$name];
    }

    /**
     * カラムの存在確認 (マジックメソッド)
     * 
     * @param  string $name 
     * @return boolean
     */
    public function __isset($name)
    {
        return isset($this->_column[$name]);
    }

    /**
     * データ格納
     *
     * _column にデータを格納します。
     * 
     * @param  array $values 
     * @return Model_ModelAbstract     */
    public function setColumns($values)
    {
        if ($values instanceof Zend_Db_Table_Row) {
            $this->_column = $values->toArray();
        } else if (is_array($values)) {
            $this->_column = $values;
        }
        return $this;
    }

    /**
     * データ取得
     *
     * _column に格納されているデータを取得します。
     * 
     * @param  string $name 
     * @return mixed
     */
    public function getColumns()
    {
        return $this->_column;
    }

    /**
     * データマッパー設定
     * 
     * @param  mixed $mapper 
     * @return Model_ModelAbstract     */
    public function setMapper($mapper)
    {
        if (is_string($mapper)) {
            $mapper = new $mapper();
        }
        if (!$mapper instanceof Model_Mapper_MapperAbstract) {
            throw new Exception('Invalid table data gateway provided');
        }
        $this->_mapper = $mapper;
        return $this;
    }

    /**
     * データマッパー呼び出し
     *
     * データマッパーを呼び出します。
     * マッパーが定義されていない場合は、クラス名から自動的に作成します。
     * 
     * @return Model_MapperAbstract
     */
    public function getMapper()
    {
        if (null === $this->_mapper) {
            $mapper = str_replace('Model_', 'Model_Mapper_', get_class($this));
            $this->setMapper($mapper);
        }
        return $this->_mapper;
    }

    /**
     * データ保存
     * 
     * @return void
     */
    public function save()
    {
        $this->getMapper()->save($this);
    }

    /**
     * データID検索
     *
     * IDからデータを検索してマッピングします。
     * 
     * @param  int $id 
     * @return Model_ModelAbstract     */
    public function find($id)
    {
        return $this->getMapper()->find($id, $this);
    }

    /**
     * 全データ取得
     *
     * テーブルの全データを取得してマッピングします。
     * 
     * @return array(Model_Abstract)
     */
    public function fetchAll($select = null)
    {
        return $this->getMapper()->fetchAll($select);
    }
    
    /**
     * 従属データ取得
     *
     * 依存テーブルのデータを取得してマッピングします。
     *
     * @param Zend_Db_Table_Row_Abstract $row
     * @return array(Model_Abstract)
     */
    public function findDependentRowset($row)
    {
        return $this->getMapper()->findDependentRowset($row);    
    }
    
    /**
     * マスタデータ取得
     *
     * マスタデータを取得して配列にします。
     *
     * @param String         $key    配列のキーとなるカラム名
     * @param String         $value  配列の値となるカラム名
     * @param Zend_Db_Select $select
     * @return array(Model_ModelAbstract)
     */
    public function fetchAllArray($key = 'cd', $value = 'name', $select = null)
    {
        return $this->getMapper()->fetchAllArray($key, $value, $select);    
    }
	
	/**
	 * WID 検索
	 *
	 * WID からデータを取得
	 *
	 * @param	Array	$wid	WID 配列
	 * @return	array(Model_ModelAbstract)
	 */
	public function getByWid($wid = array())
	{
		return $this->getMapper()->getByWid($wid);
	}
    
    /**
     * JSON 変換
     *
     * モデルデータを JSON 形式に変換します。
     *
     * @param Zend_Db_Table_Row_Abstract $row
     * @return array(Model_Abstract)
     */
    public function toJson($reclusive = false)  
    {
        // モデルのカラムデータを取得
        $return = $this->getColumns();
        
        unset($return['delete_flg']);
        unset($return['insert_datetime']);
        unset($return['insert_user']);
        unset($return['update_datetime']);
        unset($return['update_user']);
        
        foreach ($return as $key => $value) {
            // カラムデータ内の改行コードを HTML に変換
            if (is_string($value)) {
                $value = preg_replace('/\r\n/', '<br />', $value);
                $value = preg_replace('/\n/', '<br />', $value);
                $value = preg_replace('/\r/', '<br />', $value);
            }

            // key を camel_case から CamelCase に変換 (データベースカラム名漏洩防止)
            $newkey = str_replace(' ', '', ucwords(str_replace('_', ' ', $key)));
            $newkey = str_replace(array('Mst', 'Trn'), '', $newkey);
            $return[$newkey] = $value;
            unset($return[$key]);
        }
    
        if (is_array($return)) {
            foreach ($return as $key => &$value) {
                if (is_array($value)) {
                    foreach ($value as $subkey => &$subvalue) {
                        if ($subvalue instanceof Model_ModelAbstract) {
                            $subvalue = $subvalue->toJson(true);
                        }
                    }
                }
            }
        }

        if ($reclusive) {
            return $return;
        }
        return json_encode($return);  
    }  

}
